Micron Document
🎖️GitЯра🎖️

Node / meshtastic / Meshtastic-Android / files / feature / firmware / src / androidMain / kotlin / org / meshtastic / feature / firmware / AndroidFirmwareUsbManager.kt

Displaying Raw • Download

feature/firmware/src/androidMain/kotlin/org/meshtastic/feature/firmware/AndroidFirmwareUsbManager.kt 4d4070c8e1ed73a56ee2f054300a0f62e3fe2e62 (4d4070c8) Text, 5.38 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tff7b72package T7ee787org.meshtastic.feature.firmware

Tff7b72import T7ee787android.content.BroadcastReceiver
Tff7b72import T7ee787android.content.Context
Tff7b72import T7ee787android.content.Intent
Tff7b72import T7ee787android.content.IntentFilter
Tff7b72import T7ee787android.hardware.usb.UsbManager
Tff7b72import T7ee787android.os.Build
Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787kotlinx.coroutines.channels.awaitClose
Tff7b72import T7ee787kotlinx.coroutines.flow.Flow
Tff7b72import T7ee787kotlinx.coroutines.flow.callbackFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.filterNotNull
Tff7b72import T7ee787kotlinx.coroutines.flow.first
Tff7b72import T7ee787kotlinx.coroutines.flow.firstOrNull
Tff7b72import T7ee787kotlinx.coroutines.flow.map
Tff7b72import T7ee787kotlinx.coroutines.withTimeoutOrNull
Tff7b72import T7ee787org.koin.core.annotation.Single
Tff7b72import T7ee787org.meshtastic.core.network.repository.UsbRepository

T8b949e/** Manages USB-related interactions for firmware updates. */
Tf0883e@Single
Tff7b72class T56d364AndroidFirmwareUsbManagerTb4b4b4(Tff7b72private Tff7b72val Te6edf3contextTb4b4b4: Te6edf3ContextTb4b4b4, Tff7b72private Tff7b72val Te6edf3usbRepositoryTb4b4b4: Te6edf3UsbRepositoryTb4b4b4) Tb4b4b4:
Te6edf3FirmwareUsbManager Tb4b4b4{

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffserialPortKeysTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3SetTff7b72<Tffa657StringTff7b72> Tff7b72= Te6edf3usbRepositoryTb4b4b4.Te6edf3serialDevicesTb4b4b4.Te6edf3valueTb4b4b4.Te6edf3keys

Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffReturnCountTa5d6ff"Tb4b4b4) T8b949e// each failed precondition must abort without poking an arbitrary port
Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffunblockCdcPortTb4b4b4(Te6edf3excludingTb4b4b4: Te6edf3SetTff7b72<Tffa657StringTff7b72>Tb4b4b4, Te6edf3waitMillisTb4b4b4: Tffa657LongTb4b4b4, Te6edf3holdMillisTb4b4b4: Tffa657LongTb4b4b4)Tb4b4b4: Tffa657Boolean Tb4b4b4{
T8b949e// The erase image enumerates a moment after the write, so poll rather than sampling once.
Tff7b72val Te6edf3driver Tff7b72=
Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3waitMillisTb4b4b4) Tb4b4b4{
Te6edf3usbRepositoryTb4b4b4.Te6edf3serialDevices
Tb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3devices Tff7b72-Tff7b72> Te6edf3devicesTb4b4b4.Te6edf3entriesTb4b4b4.Te6edf3firstOrNull Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3key Tff7b72!in Te6edf3excluding Tb4b4b4}Tff7b72?.Te6edf3value Tb4b4b4}
Tb4b4b4.Te6edf3filterNotNullTb4b4b4(Tb4b4b4)
Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72if Tb4b4b4(Te6edf3driver Tff7b72=Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffNo new serial port appeared within Tffd700${Te6edf3waitMillisTffd700}Ta5d6ffms; cannot unblock the erase imageTa5d6ff" Tb4b4b4}
Tff7b72return Tff7b72false
Tb4b4b4}

T8b949e// device_filter.xml lists no bootloader-mode ids (and none at all for Seeed's 0x2886), so no implicit grant
T8b949e// exists here — an explicit request is the only route. Bounded by waitMillis too: requestPermission can
T8b949e// return emptyFlow() (no UsbManager available), and first() on that throws instead of denying cleanly —
T8b949e// firstOrNull() under a timeout treats both "empty flow" and "unanswered dialog" as a plain denial.
Tff7b72if Tb4b4b4(
Tff7b72!Te6edf3usbRepositoryTb4b4b4.Te6edf3hasPermissionTb4b4b4(Te6edf3driverTb4b4b4.Te6edf3deviceTb4b4b4) Tff7b72&Tff7b72&
Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3waitMillisTb4b4b4) Tb4b4b4{ Te6edf3usbRepositoryTb4b4b4.Te6edf3requestPermissionTb4b4b4(Te6edf3driverTb4b4b4.Te6edf3deviceTb4b4b4)Tb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4) Tb4b4b4} Tff7b72!Tff7b72= Tff7b72true
Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffUSB permission denied; cannot unblock the erase imageTa5d6ff" Tb4b4b4}
Tff7b72return Tff7b72false
Tb4b4b4}

Tff7b72return Te6edf3usbRepositoryTb4b4b4.Te6edf3pokeDtrTb4b4b4(Te6edf3driverTb4b4b4, Te6edf3holdMillisTb4b4b4)
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffensureSerialPermissionTb4b4b4(Te6edf3waitMillisTb4b4b4: Tffa657LongTb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3withTimeoutOrNullTb4b4b4(Te6edf3waitMillisTb4b4b4) Tb4b4b4{
T8b949e// The updated firmware enumerates a while after the UF2 is consumed; poll rather than sampling once.
Tff7b72val Te6edf3driver Tff7b72=
Te6edf3usbRepositoryTb4b4b4.Te6edf3serialDevicesTb4b4b4.Te6edf3map Tb4b4b4{ Te6edf3devices Tff7b72-Tff7b72> Te6edf3devicesTb4b4b4.Te6edf3valuesTb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4) Tb4b4b4}Tb4b4b4.Te6edf3filterNotNullTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3firstTb4b4b4(Tb4b4b4)
Tff7b72if Tb4b4b4(Te6edf3usbRepositoryTb4b4b4.Te6edf3hasPermissionTb4b4b4(Te6edf3driverTb4b4b4.Te6edf3deviceTb4b4b4)Tb4b4b4) Tff7b72returnTf0883e@withTimeoutOrNull Tff7b72true
T8b949e// The permission dialog itself must share this budget — otherwise an unanswered dialog leaves the
T8b949e// caller (the post-update verification flow) parked forever instead of falling back to auto-recovery.
T8b949e// firstOrNull(): requestPermission can return emptyFlow() (no UsbManager available), and first() on
T8b949e// that throws instead of denying cleanly.
Te6edf3usbRepositoryTb4b4b4.Te6edf3requestPermissionTb4b4b4(Te6edf3driverTb4b4b4.Te6edf3deviceTb4b4b4)Tb4b4b4.Te6edf3firstOrNullTb4b4b4(Tb4b4b4) Tff7b72=Tff7b72= Tff7b72true
Tb4b4b4}
Tff7b72?: Te6edf3run Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffUSB permission preflight did not complete within Tffd700${Te6edf3waitMillisTffd700}Ta5d6ffmsTa5d6ff" Tb4b4b4}
Tff7b72false
Tb4b4b4}

T8b949e/** Observe when a USB device is detached. */
Tff7b72override Tff7b72fun Td2a8ffdeviceDetachFlowTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3FlowTff7b72<Tffa657UnitTff7b72> Tff7b72= Te6edf3callbackFlow Tb4b4b4{
Tff7b72val Te6edf3receiver Tff7b72=
Tff7b72object Tb4b4b4: T56d364BroadcastReceiverTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72override Tff7b72fun Td2a8ffonReceiveTb4b4b4(Te6edf3contextTb4b4b4: Te6edf3ContextTb4b4b4, Te6edf3intentTb4b4b4: Te6edf3IntentTb4b4b4) Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3intentTb4b4b4.Te6edf3action Tff7b72=Tff7b72= Te6edf3UsbManagerTb4b4b4.Te6edf3ACTION_USB_DEVICE_DETACHEDTb4b4b4) Tb4b4b4{
Te6edf3trySendTb4b4b4(Tffa657UnitTb4b4b4)Tb4b4b4.Te6edf3isSuccess
Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tff7b72val Te6edf3filter Tff7b72= Te6edf3IntentFilterTb4b4b4(Te6edf3UsbManagerTb4b4b4.Te6edf3ACTION_USB_DEVICE_DETACHEDTb4b4b4)

Tff7b72if Tb4b4b4(Te6edf3BuildTb4b4b4.Te6edf3VERSIONTb4b4b4.Te6edf3SDK_INT Tff7b72>Tff7b72= Te6edf3BuildTb4b4b4.Te6edf3VERSION_CODESTb4b4b4.Te6edf3TIRAMISUTb4b4b4) Tb4b4b4{
Te6edf3contextTb4b4b4.Te6edf3registerReceiverTb4b4b4(Te6edf3receiverTb4b4b4, Te6edf3filterTb4b4b4, Te6edf3ContextTb4b4b4.Te6edf3RECEIVER_NOT_EXPORTEDTb4b4b4)
Tb4b4b4} Tff7b72else Tb4b4b4{
Tf0883e@SuppressTb4b4b4(Ta5d6ff"Ta5d6ffUnspecifiedRegisterReceiverFlagTa5d6ff"Tb4b4b4)
Te6edf3contextTb4b4b4.Te6edf3registerReceiverTb4b4b4(Te6edf3receiverTb4b4b4, Te6edf3filterTb4b4b4)
Tb4b4b4}

Te6edf3awaitClose Tb4b4b4{
Te6edf3runCatching Tb4b4b4{ Te6edf3contextTb4b4b4.Te6edf3unregisterReceiverTb4b4b4(Te6edf3receiverTb4b4b4) Tb4b4b4}
Tb4b4b4.Te6edf3onFailure Tb4b4b4{ Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Tffa657itTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to unregister USB receiverTa5d6ff" Tb4b4b4} Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.06s